local skynet = require "skynet"
local netpack = require "skynet.netpack"
local socket = require "skynet.socket"
local crypt = require "skynet.crypt"
local sprotoloader = require "sprotoloader"
local snax = require "skynet.snax"
local sharedata = require "skynet.sharedata"
local urllib = require "http.url"
local utils = require "utils"

local ws_server = require "ws.ws_server2"

local fid,addr,gate = ...

local client_fd

local host
local make_request

local CMD = {}
local REQUEST = {}
local RESPONSE = {}

local handle = {}

local itemmgr

local data = {
	uid = 0,
-- 	base = nil,
-- 	data = nil
}

local function send_package(pack)
	local package = string.pack(">s2",pack)
	server:send_binary(package)
end

local function print_request(name, args)
	if name == "syncTime" then
		return
	end
	log_print("REQUEST ---------------",data.uid, name)
	if args then
		for k,v in pairs(args) do
			log_print(k,':',v)
		end
	end
	log_print("end ---------------")
end

local function print_response(session, args)
	log_print("RESPONSE ---------------",data.uid, session)
	if args then
		for k,v in pairs(args) do
			log_print(k,':',v)
		end
	end
	log_print("end ---------------")
end

local function print_package(t, ...)
	if t == "REQUEST" then
		print_request(...)
	else
		assert(t == "RESPONSE")
		print_response(...)
	end
end

local function unpack_package(text)
	local size = #text
	if size < 2 then
		return 0
	end
	local s = text:byte(1) * 256 + text:byte(2)
	if size < s+2 then
		return 0
	end
	return s,text:sub(3,2+s)
end

function CMD.send_close()
	server:close()
end

function CMD.send_package(msg,pack)
	log_print("send_package -----------",data.uid, msg)
	if server then
		for k,v in pairs(pack) do
			log_print(k,':')
			log_dump(v)
		end
		send_package(make_request(msg,pack))
	else
		skynet.error("palyer off-line ",data.uid)
	end
	log_print("end ---------------")
end


function CMD.addGold(gold)
	if gold == 0 then
		return
	end
	local gold = usermgr.req.addGold(data.uid,gold)
	RESPONSE.getGold(gold)
end

function CMD.updateItem(item)
	itemmgr.req.updateItem(item)
	RESPONSE.itemList({item})
end

function CMD.updateItemList(itemlist)
	for i,v in ipairs(itemlist) do
		itemmgr.req.updateItem(v)
	end
	RESPONSE.itemList(itemlist)
end

function RESPONSE.getGold(gold)
	if gold == 0 then
		return
	end
	CMD.send_package("getGold",{gold = gold})
end

function RESPONSE.itemList(itemlist)
	if #itemlist == 0 then
		return
	end
	CMD.send_package("itemList",{itemlist = itemlist})
end

function REQUEST:itemList()
	local list = itemmgr.req.getItemList(data.uid)
	local arr = {}
	for k,v in pairs(list) do
		arr[#arr + 1] = v
	end
	return {itemlist = arr}
end

function REQUEST:itemAdd()
	local item = itemmgr.req.addItem(data.uid,self.configId,self.num)
	return {result = 0,item = item}
end

function REQUEST:itemUse()
	local result,item,list = skynet.call("itemd","lua","itemUse",
						data.uid,self.uid,self.num)
	if result == 0 then
		return {result = 0,uid = item.uid,num = item.num,itemlist = list}
	end
	return {result = result}
end

--------------------------------------------------

local function updateDay()
	if server then
		log_print("updateDay",data.uid)
		usermgr.req.updateday(data.uid)
	end
end

local function request(name, args, response)
	-- print(name)
    local f = assert(REQUEST[name])
	local r = f(args)
	-- skynet.error(response)
    if response and r then
        -- 生成回应包(response是一个用于生成回应包的函数。)
		-- 处理session对应问题
		if name ~= "syncTime" then
			log_print("response ---------------",data.uid)
			for k,v in pairs(r) do
				log_print(k,':')
				log_dump(v)
			end
			log_print("end ---------------")
		end
        return response(r)
    end
end

handle.on_open = function(ws,url)
	skynet.error("ws open",url)
	local path, query = urllib.parse(url)   
	if path == "/game" or path == "/wsgame/game" then
		local q = urllib.parse_query(query)
		local isauth = false
		local uid
		if q["token"] then
			isauth,uid = skynet.call(".logind", "lua", "online_auth", q["token"])
		end
		if isauth then
			data.uid = uid
			usermgr.req.dataload(data.uid)

			RESPONSE.userData()
			local logincount = statisticsmgr.req.getdata(data.uid,"logincount")
			print("logincount ",logincount)
			if logincount > 1 then
				RESPONSE.signDay()
			end

			skynet.timeout(utils.getDistanceTime(0,1) * 100,updateDay)
			
			skynet.send(gate, "lua", "open",ws.id,data.uid)
		else
			log_error("isauth ",isauth)
			server:send_close()
		end
	else
		server:send_close()
	end
end 

-- handle.on_text = function(ws,data)
-- 	-- data = crypt.base64decode(data)
-- 	-- skynet.error("on_text",data)
-- 	-- server:send_text(data)
-- 	local ret = host:dispatch(data)
-- 	skynet.error(ret)
-- end 


handle.on_binary = function(ws,data)
	-- data = crypt.base64decode(data)
	-- skynet.error("on_binary",data)
	local len, v = unpack_package(data)

	local t,msg,data,response = host:dispatch(v)
	print_package(t,msg,data)
	if t == "REQUEST" then
		local ok, result  = pcall(request, msg,data,response)
		if ok then
			if result then
				send_package(result)
			end
		else
			skynet.error(result)
		end
	else
		-- "RESPONSE"
	end

end 

-- handle.on_message = function(ws,msg)
-- 	skynet.error("message:", msg)
-- 	local package = string.pack(">s2", msg)
	
-- 	server:send_binary("nihao")
-- end

handle.on_close = function(ws)
	skynet.error("wsagent close",ws.id,data.uid)
	skynet.send(gate, "lua", "close",ws.id,data.uid)

	client_fd = nil
	server = nil
	skynet.exit()
end 

skynet.start(function()
	usermgr = snax.uniqueservice("usermgr")
    itemmgr = snax.uniqueservice("itemmgr")
	
	host = sprotoloader.load(1):host()
	make_request = host:attach(sprotoloader.load(2))

	fid = tonumber(fid)
	client_fd = fid
	server = ws_server.new(fid, handle)

	skynet.dispatch("lua", function(_,_, command, ...)
		local f = CMD[command]
		if f then
			skynet.ret(skynet.pack(f(...)))
		else
			skynet.error("no f",command)
		end
		
	end)
end)
